package org.glandais.games.rebondrobots.solver;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.glandais.games.rebondrobots.board.Board;
import org.glandais.games.rebondrobots.board.Direction;
import org.glandais.games.rebondrobots.board.Goal;
import org.glandais.games.rebondrobots.board.RobotColor;
import org.glandais.games.rebondrobots.board.Robots;

public class BruteForceMove extends RobotMove {

	private BruteForceMove parentMove;

	private List<BruteForceMove> childMoves;

	private Board board;

	private Set<Robots> done;

	private Goal goal;

	public BruteForceMove(BruteForceMove parentMove, Board board,
			Robots robots, Set<Robots> done, Goal goal) {
		super();
		this.parentMove = parentMove;
		this.board = board;
		this.robots = robots;
		this.done = done;
		this.goal = goal;
		this.childMoves = new ArrayList<BruteForceMove>();
	}

	public BruteForceMove move() {

		Direction[] directions = Direction.values();
		// For each color
		RobotColor[] colors = RobotColor.values();

		BruteForceMove goodMove = null;

		for (RobotColor color : colors) {
			// For each direction
			for (Direction direction : directions) {
				if (goodMove == null) {
					Robots newRobots = robots.move(board, color, direction);
					if (!done.contains(newRobots)) {
						done.add(newRobots);
						BruteForceMove childMove = new BruteForceMove(this,
								board, newRobots, done, goal);
						childMoves.add(childMove);

						childMove.setDirection(direction);
						childMove.setFromCell(robots.getPosition(color));
						childMove.setToCell(newRobots.getPosition(color));
						childMove.setRobot(color);

						// board.saveToPNG(
						// new File("img/" + childMove.getMovesString()
						// + "png"), newRobots, childMove, goal);

						if (newRobots.getPosition(goal.getColor()).equals(
								goal.getCell())) {
							// Solution !
							goodMove = childMove;
						}
					}
				}
			}
		}

		return goodMove;
	}

	private String getMovesString() {
		String result = "";
		if (parentMove != null) {
			result = parentMove.getMovesString();
		}
		if (getRobot() != null && getDirection() != null) {
			char robot = getRobot().name().charAt(0);
			char direction = getDirection().name().charAt(0);
			result = result + robot + direction + ".";
		}
		return result;
	}

	public Solution solve() {
		int level = 0;
		BruteForceMove goodMove = null;

		done.add(robots);

		if (robots.getPosition(goal.getColor()).equals(goal.getCell())) {
			// Solution !
			goodMove = this;
		}

		while (goodMove == null) {
			List<BruteForceMove> toTest = new ArrayList<BruteForceMove>();
			collectChildMoves(level, toTest);
			for (BruteForceMove bruteForceMove : toTest) {
				if (goodMove == null) {
					goodMove = bruteForceMove.move();
				}
			}
			level++;
		}

		return goodMove.toSolution();
	}

	private void collectChildMoves(int level, List<BruteForceMove> toTest) {
		if (level == 0) {
			toTest.add(this);
		} else {
			for (BruteForceMove bruteForceMove : childMoves) {
				bruteForceMove.collectChildMoves(level - 1, toTest);
			}
		}
	}

	private Solution toSolution() {
		Solution solution = new Solution();

		List<RobotMove> moves = new LinkedList<RobotMove>();
		createMoves(moves);
		solution.setMoves(moves);
		return solution;
	}

	private void createMoves(List<RobotMove> moves) {
		if (parentMove != null) {
			parentMove.createMoves(moves);
		}
		moves.add(this);
	}

}
